home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / dfue / elcheapofax / faxcmd / libfax / rcs / send.c,v < prev    next >
Text File  |  1995-03-09  |  14KB  |  614 lines

  1. head    1.6;
  2. access;
  3. symbols
  4.     OCT93:1.6;
  5. locks;
  6. comment    @ * @;
  7.  
  8.  
  9. 1.6
  10. date    93.10.25.02.20.15;    author Rhialto;    state Exp;
  11. branches;
  12. next    1.5;
  13.  
  14. 1.5
  15. date    93.09.18.20.23.52;    author Rhialto;    state Exp;
  16. branches;
  17. next    1.4;
  18.  
  19. 1.4
  20. date    93.09.18.20.16.23;    author Rhialto;    state Exp;
  21. branches;
  22. next    1.3;
  23.  
  24. 1.3
  25. date    93.07.13.05.41.27;    author Rhialto;    state Exp;
  26. branches;
  27. next    1.2;
  28.  
  29. 1.2
  30. date    93.06.11.16.15.25;    author Rhialto;    state Exp;
  31. branches;
  32. next    1.1;
  33.  
  34. 1.1
  35. date    93.06.11.15.19.27;    author Rhialto;    state Exp;
  36. branches;
  37. next    ;
  38.  
  39.  
  40. desc
  41. @Initiate, send data, terminate
  42. @
  43.  
  44.  
  45. 1.6
  46. log
  47. @Make +FBOR flexible.
  48. @
  49. text
  50. @/* $Id: send.c,v 1.5 1993/09/18 20:23:52 Rhialto Exp $
  51.  * $Log: send.c,v $
  52.  * Revision 1.5  1993/09/18  20:23:52  Rhialto
  53.  * Break out faxmodem_sync() from faxmodem_initiate_call(), so you
  54.  * must call it after faxmodem_open(). This allows additional commands
  55.  * before dialing.
  56.  *
  57.  * Revision 1.4  1993/09/18  20:16:23  Rhialto
  58.  * Add (compile time) choice for +FBOR= value.
  59.  *
  60.  * Revision 1.3  1993/07/13  05:41:27  Rhialto
  61.  * Support for modems that are already fax-connected when we startup.
  62.  *
  63.  * Revision 1.2  1993/06/11  16:15:25  Rhialto
  64.  * First real RCS checkin
  65.  *
  66.  */
  67. /*
  68.  * This file is part of El Cheapo Fax. All modifications relative to the
  69.  * base source are (C) Copyright 1993 by Olaf 'Rhialto' Seibert.
  70.  * All rights reserved. The GNU General Public License applies.
  71.  */
  72. /*
  73.   This file is part of the NetFax system.
  74.  
  75.   (c) Copyright 1989 by David M. Siegel and Sundar Narasimhan.
  76.       All rights reserved.
  77.  
  78.     This program is free software; you can redistribute it and/or modify
  79.     it under the terms of the GNU General Public License as published by
  80.     the Free Software Foundation.
  81.  
  82.     This program is distributed in the hope that it will be useful,
  83.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  84.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  85.     GNU General Public License for more details.
  86.  
  87.     You should have received a copy of the GNU General Public License
  88.     along with this program; if not, write to the Free Software
  89.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  90. */
  91.  
  92. #include <stdio.h>
  93.  
  94. #include "log.h"
  95. #include "c2proto.h"
  96. #include "response.h"
  97. #include "swap.h"
  98. #include "read.h"
  99. #include "write.h"
  100. #include "tty.h"
  101. #include "send.h"
  102. #include "gen.h"
  103.  
  104. /*
  105.   Maximum amount of data to send to the modem in one write call:
  106. */
  107. #define SEND_CHUNK 1024
  108.  
  109. static int dial(FaxModem * f, char * phonenum);
  110. static int start_xmit(FaxModem * f, int df, int vr, int wd, int ln);
  111. static int end_page(FaxModem * f);
  112. static int end_xmit(FaxModem * f);
  113. static int process_send_response(FaxModem * f);
  114. static int send_page(FaxModem * f, int fd, int last_page);
  115. int read(int, char *, int);
  116. int lseek(int, long, int);
  117.  
  118. /*
  119.  * Dial a number: ATDT
  120.  *
  121.  * Return codes:
  122.  *     0    ok, number has been dialed.
  123.  *    -1    dial failed.
  124.  */
  125. static int dial(f, phonenum)
  126.      FaxModem *f;
  127.      char *phonenum;
  128. {
  129.     log(L_NOTICE, "dialing: %s", phonenum);
  130.  
  131.     if (FAX_ISSET(f,FAX_F_CONNECT))
  132.     return 0;
  133.  
  134.     init_modem_response(f);
  135.  
  136.     if (fdprintf(f->fd, "ATDT%s\r", phonenum) < 0)
  137.       return (-1);
  138.  
  139.     if (get_modem_response(f, TIMEOUT_CONNECT) < 0)
  140.       return (-1);
  141.  
  142.     /*
  143.      * Save away the last numeric result as the result of this
  144.      * dial operation.    This makes it handy to check what
  145.      * happened on the last dial.
  146.      */
  147.     f->dialer_code = f->result;
  148.  
  149.     return (0);
  150. }
  151.  
  152. /*
  153.  * Dial to a remote fax machine. (Modem must have been sync'ed first)
  154.  *
  155.  * Return codes:
  156.  *     0    connection to remote modem has been established.
  157.  *    -1    connection failed.
  158.  */
  159. int faxmodem_initiate_call(f, dialstring)
  160.      FaxModem *f;
  161.      char *dialstring;
  162. {
  163.     /*
  164.      * Set phase C data bit order.
  165.      *
  166.      * The interfax firmware has a bug with received data in
  167.      * bitreverse=1 mode, so I will leave it in bor=0, and fudge the
  168.      * data in software. (This is not necessarily true anymore)
  169.      */
  170.     if (faxmodem_bit_reverse(f, bor_value) < 0) {
  171.     log(L_NOTICE, "setting modem to bit reverse=%d failed", bor_value);
  172.     return (-1);
  173.     }
  174.     /*
  175.      * Initiate the call to the remote modem.
  176.      */
  177.     if (dial(f, dialstring) < 0) {
  178.     log(L_NOTICE, "dial failed");
  179.     return (-1);
  180.     }
  181.  
  182.     return (0);
  183. }
  184.  
  185. /*
  186.  * Begin or continue sending: +FDT
  187.  *
  188.  * Send the appropriate commands to the fax modem to start transmission
  189.  * of a page.  After sending the start commands, the modem will respond
  190.  * with a message that ends with CONNECT.  For now, we don't parse any
  191.  * of this message, we just look for the CONNECT.  In addition, the
  192.  * modem will signal to us that we should start sending G3 data by
  193.  * issuing an XON.  Thus, we force an XOFF.  THe subsequent writes
  194.  * to the modem will not start to drain until the XON occurs.  Note
  195.  * that this part of the protocol may change, according to the most
  196.  * recent documention.
  197.  *
  198.  * Set desired transmission params with +FDT=DF,VR,WD,LN
  199.  *   DF = Data Format :     0  [1-d huffman]
  200.  *   VR = Vertical Res :    1  [196 dpi (fine)]
  201.  *   WD = width :        0  [ 1728 pixels]
  202.  *   LN = page length :     2  [ Unlimited ]
  203.  *
  204.  * Return codes:
  205.  *     0    ok, proceed with sending data
  206.  *    -1    setup failed, not ready to send.
  207.  */
  208. static int start_xmit(f, df, vr, wd, ln)
  209.      FaxModem *f;
  210.      int df, vr, wd, ln;
  211. {
  212.     log(L_NOTICE, "setting xmit params: df %d vr %d wd %d ln %d", df, vr, wd, ln);
  213.  
  214.     if (fdprintf(f->fd, "AT+FDT=%d,%d,%d,%d\r", df, vr, wd, ln) < 0)
  215.       return (-1);
  216.  
  217.     /*
  218.      * Wait for the output to the modem to complete, and then stop
  219.      * all further output (via an XOFF).  The modem will eventually
  220.      * respond with an XON, allowing the data transmission to begin.
  221.      */
  222.     tcdrain(f->fd);
  223.     ioctl(f->fd, TCXONC, TCOOFF);
  224.  
  225.     /*
  226.      * Make sure that we get the CONNECT message from the modem.
  227.      */
  228.     return (get_modem_response(f, TIMEOUT_FDT));
  229. }
  230.  
  231. /*
  232.  * end of page, another page from same document is coming: +FET=0
  233.  *
  234.  * This transmit page punctuation command is issued after a +FDT has
  235.  * been issued, and indicates that the current page has completed,
  236.  * and another page from the same document is about to be sent.
  237.  *
  238.  * Return codes:
  239.  *     0    all ok
  240.  *    -1    modem response error
  241.  */
  242. static int end_page(f)
  243.      FaxModem *f;
  244. {
  245.     log(L_NOTICE, "end of current page, another page will be sent");
  246.  
  247.     if (fdprintf(f->fd, "AT+FET=0\r") < 0)
  248.       return (-1);
  249.  
  250.     return (get_modem_response(f, TIMEOUT_END_PAGE));
  251. }
  252.  
  253. /*
  254.  * End of page and end of document: +FET=2
  255.  *
  256.  * This transmit page punctuation command is issued after a +FDT has
  257.  * been issued, and incates that the current page has completed,
  258.  * and the document is complete as well.
  259.  *
  260.  * Return codes:
  261.  *     0    all ok
  262.  *    -1    modem response error
  263.  */
  264. static int end_xmit(f)
  265.      FaxModem *f;
  266. {
  267.     log(L_NOTICE, "end of current page, document is now complete");
  268.  
  269.     if (fdprintf(f->fd, "AT+FET=2\r") < 0)
  270.       return (-1);
  271.  
  272.     return (get_modem_response(f, TIMEOUT_END_XMIT));
  273. }
  274.  
  275. /*
  276.  * When sending data, it is possible to get a CAN message from
  277.  * the remote fax.  This message indicates that the send should
  278.  * be aborted.    The DLE ETX sequence should be sent to the DCE
  279.  * to ack the abort.
  280.  *
  281.  * Return codes:
  282.  *    0    all ok, proceed with sending
  283.  *     -1    send failed, check modem flags for more details
  284.  */
  285. static int process_send_response(f)
  286.      FaxModem *f;
  287. {
  288.     char resp[128];
  289.     int resp_len;
  290.     int i;
  291.  
  292.     /*
  293.      * We poll the fd for any input.  If none is available, all
  294.      * is fine.  If we get any input at all, it should be a CAN
  295.      * command, as that is all that the protocol allows.  However,
  296.      * to be safe we toss out any other junk that may come in.
  297.      */
  298.     switch (resp_len = pread(f->fd, resp, sizeof(resp))) {
  299.       case -1:
  300.     log(L_ERR, "send_page: poll failed: %m");
  301.     f->status = MODEM_STATUS_FAILED;
  302.     return (-1);
  303.       case 0:
  304.     return (0);
  305.       default:
  306.     log(L_INFO, "process_send_response: got \"%.*s\"", resp_len, resp);
  307.     for (i = 0; i < resp_len; i++) {
  308.         if ((resp[i] & 0x7f) == CAN) {
  309.         log(L_NOTICE, "remote fax has canceled transmission");
  310.         fdprintf(f->fd, "%c%c", DLE, ETX);
  311.         f->flags |= FAX_F_CANCELED;
  312.         return (-1);
  313.         }
  314.     }
  315.     return (0);
  316.     }
  317. }
  318.  
  319. /*
  320.  * Actually send a page.  We assume that we have dialed and connected
  321.  * to the remote fax machine, and that all is ready for starting
  322.  * the actually transmission.
  323.  *
  324.  * Return codes:
  325.  *     0    page has been succesfully sent
  326.  *    -1    send of page failed.
  327.  * XXX Should support files with more than 1 page
  328.  */
  329. static int send_page(f, fd, last_page)
  330.      FaxModem *f;
  331.      int fd;
  332.      int last_page;
  333. {
  334.     log(L_INFO, "sending g3 file");
  335.  
  336.     /*
  337.      * Setup things for transmission.
  338.      */
  339.     if (start_xmit(f, DF_1DHUFFMAN, VR_FINE, WD_1728, LN_UNLIMITED) < 0)
  340.       return (-1);
  341.  
  342.     /*
  343.      * Allow modem to send ^S to us.  Don't use flow control in the
  344.      * other direction, since we need to pass 8 bits.
  345.      */
  346.     tty_fc(f->fd, FC_OUTPUT_ON);
  347.  
  348.     /*
  349.      * Now send the page.
  350.      */
  351.     for (;;) {
  352.     unsigned char buf[SEND_CHUNK];
  353.     unsigned char buf_copy[SEND_CHUNK*2];
  354.     int nchars, ochars;
  355.     int i;
  356.  
  357.     /*
  358.      * Read in a hunk of data.
  359.      */
  360.     if ((nchars = read(fd, buf, sizeof(buf))) < 0) {
  361.         log(L_ERR, "send_page: read failed: %m");
  362.         tty_fc(f->fd, FC_BOTH_ON);
  363.         return (-1);
  364.     }
  365.     if (nchars == 0)
  366.       break;
  367.  
  368.     /*
  369.      * Reverse and stuff buffer characters:
  370.      */
  371.     ochars = 0;
  372.     for (i = 0; i < nchars; i++) {
  373.         buf_copy[ochars] = swap_bits(buf[i]);
  374.         if (buf_copy[ochars++] == DLE)
  375.           buf_copy[ochars++] = DLE;
  376.     }
  377.  
  378.     /*
  379.      * Write out the buffer to the modem.
  380.      */
  381.     if (nwrite(f->fd, (char *)buf_copy, ochars) != ochars) {
  382.         log(L_ERR, "send_page: write to modem failed: %m");
  383.         tty_fc(f->fd, FC_BOTH_ON);
  384.         return (-1);
  385.  
  386.     }
  387.  
  388.     /*
  389.      * Check for any response from the modem.
  390.      */
  391.     if (process_send_response(f) < 0) {
  392.         tty_fc(f->fd, FC_BOTH_ON);
  393.         return (-1);
  394.     }
  395.     }
  396.  
  397.     fdprintf(f->fd, "%c%c", DLE, ETX);
  398.  
  399.     tty_fc(f->fd, FC_BOTH_ON);
  400.  
  401.     if (get_modem_response(f, TIMEOUT_SEND_PAGE) < 0) {
  402.     log(L_NOTICE, "an error sending the file has occured");
  403.     return (-1);
  404.     } else
  405.       log(L_INFO, "send of file has completed");
  406.  
  407.     if (last_page)
  408.       return (end_xmit(f));
  409.     else
  410.       return (end_page(f));
  411. }
  412.  
  413. /*
  414.  * Send off a page.  If a retransmit is requested, try up to tries number
  415.  * of times.  If this is the last page of the transmission, set last_page
  416.  * to be true.    The G3 file to send is opened on the given fd.
  417.  *
  418.  * Return codes:
  419.  *    0    the page was successfully sent
  420.  *     -1    the send failed, see the modem flags for more details
  421.  */
  422. int faxmodem_send_page(f, fd, last_page, tries)
  423.      FaxModem *f;
  424.      int fd;
  425.      int last_page;
  426.      int tries;
  427. {
  428.     int i;
  429.     long seekpos;
  430.  
  431.     seekpos = lseek(fd, 0, 1);      /* Rhialto */
  432.  
  433.     for (i = 0; i < tries; i++) {
  434.     if (send_page(f, fd, last_page) < 0)
  435.       return (-1);
  436.  
  437.     /*
  438.      * If hangup was detected and not last page, then return
  439.      * with an error condition.
  440.      */
  441.     if (last_page) {
  442.         if (FAX_ISSET(f, FAX_F_FHNG) && (f->hangup_code != 0)) {
  443.         log(L_NOTICE, "hangup on last page: %d", f->hangup_code);
  444.         return (-1);
  445.         }
  446.     } else {
  447.         if (FAX_ISSET(f, FAX_F_FHNG)) {
  448.         log(L_NOTICE, "hangup code received while sending pages");
  449.         return (-1);
  450.         }
  451.     }
  452.  
  453.     /*
  454.      * Make sure we got a post page response.
  455.      */
  456.     if (!FAX_ISSET(f, FAX_F_FPTS)) {
  457.         log(L_NOTICE, "didn't receive post page response");
  458.         return (-1);
  459.     }
  460.  
  461.     switch (f->ppr_code) {
  462.       case PPR_MCF:
  463.         /* page good */
  464.         return (0);
  465.  
  466.       case PPR_RTN:
  467.       case PPR_RTP:
  468.         /* retrans requested for both these cases */
  469.         break;
  470.  
  471.       case PPR_PIN:
  472.       case PPR_PIP:
  473.         /* interrupt requested, what do we do here? assume failure */
  474.         return (-1);
  475.  
  476.       default:
  477.         log(L_ERR, "unknown ppr code received");
  478.         return (-1);
  479.     }
  480.     lseek(fd, seekpos, 0);  /* Rhialto */
  481.     }
  482.  
  483.     f->flags |= FAX_F_RETRIES;
  484.  
  485.     log(L_NOTICE, "failed to successfully send page");
  486.  
  487.     return (-1);
  488. }
  489.  
  490. #ifdef DEBUG
  491. FaxModem fm;
  492.  
  493. int send_test(phone)
  494.      char *phone;
  495. {
  496.     int fd;
  497.  
  498.     log_set_level(LOG_INFO);
  499.  
  500.     if (faxmodem_open(&fm, "/dev/ttyb") < 0) {
  501.     fprintf(stderr, "open failed\n");
  502.     return (-1);
  503.     }
  504.  
  505.     if (faxmodem_initiate_call(&fm, phone) < 0 || !FAX_CONNECTED(&fm)) {
  506.     fprintf(stderr, "connection failed\n");
  507.     return (-1);
  508.     }
  509.  
  510.     if ((fd = open("test.g3.0", O_RDONLY)) < 0) {
  511.     fprintf(stderr, "can't open test file\n");
  512.     faxmodem_close(&fm);
  513.     return (-1);
  514.     }
  515.  
  516.     if (faxmodem_send_page(&fm, fd, TRUE, 3) < 0)
  517.       fprintf(stderr, "send failed\n");
  518.     else
  519.       fprintf(stderr, "send was successful\n");
  520.  
  521.     faxmodem_hangup(&fm);
  522.     faxmodem_close(&fm);
  523.  
  524.     return (0);
  525. }
  526. #endif
  527. @
  528.  
  529.  
  530. 1.5
  531. log
  532. @Break out faxmodem_sync() from faxmodem_initiate_call(), so you
  533. must call it after faxmodem_open(). This allows additional commands
  534. before dialing.
  535. @
  536. text
  537. @d1 1
  538. a1 1
  539. /* $Id: send.c,v 1.4 1993/09/18 20:16:23 Rhialto Exp $
  540. d3 5
  541. a67 3
  542. #if BOR_VALUE == BOR_C_REV
  543. #define swap_bits(x)    (x)
  544. #endif
  545. d121 2
  546. a122 2
  547.     if (faxmodem_bit_reverse(f, BOR_VALUE) < 0) {
  548.     log(L_NOTICE, "setting modem to bit reverse=%d failed", BOR_VALUE);
  549. d179 1
  550. a179 1
  551.     return (get_modem_response(f, 120));
  552. @
  553.  
  554.  
  555. 1.4
  556. log
  557. @Add (compile time) choice for +FBOR= value.
  558. @
  559. text
  560. @d1 1
  561. a1 1
  562. /* $Id: send.c,v 1.3 1993/07/13 05:41:27 Rhialto Exp $
  563. d3 3
  564. d102 1
  565. a102 1
  566.  * Sync and dial to a remote fax machine.
  567. a111 3
  568.     if (faxmodem_sync(f, 10) < 0)
  569.       return (-1);
  570.  
  571. @
  572.  
  573.  
  574. 1.3
  575. log
  576. @Support for modems that are already fax-connected when we startup.
  577. @
  578. text
  579. @d1 1
  580. a1 1
  581. /* $Id: send.c,v 1.2 1993/06/11 16:15:25 Rhialto Exp $
  582. d3 3
  583. d60 3
  584. d117 1
  585. a117 1
  586.      * data in software.
  587. d119 2
  588. a120 2
  589.     if (faxmodem_bit_reverse(f, 0) < 0) {
  590.     log(L_NOTICE, "setting modem to bit reverse failed");
  591. @
  592.  
  593.  
  594. 1.2
  595. log
  596. @First real RCS checkin
  597. @
  598. text
  599. @d1 5
  600. a5 2
  601. /* $Id$
  602.  * $Log$
  603. d70 3
  604. @
  605.  
  606.  
  607. 1.1
  608. log
  609. @Initial revision
  610. @
  611. text
  612. @d1 3
  613. @
  614.